#include "stdafx.h"
#include "CHReportListBase.h"
#include "CHMemDC.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CHReportListBase::CHReportListBase()
{
	m_pListCtrl = NULL;
	m_nLineHeight = 16;
	m_nIconWidth = 1;
	m_nSortedCol = -1;

	m_bAscending = FALSE;
	m_bAutoSave  = FALSE;
	m_bAutoFont	 = TRUE;
	
	m_strSection = _T("Section");
	m_strEntry = _T("Entry");
	m_strDefault = _T("");

	m_clrText = ::GetSysColor(COLOR_WINDOWTEXT);
	m_clrTextBk = ::GetSysColor(COLOR_WINDOW);
}

CHReportListBase::~CHReportListBase()
{

}

void CHReportListBase::SaveColumnWidths()
{
}

void CHReportListBase::LoadColumnWidths()
{
}

void CHReportListBase::SetCurSel(int nRow)
{
	ASSERT(m_pListCtrl != NULL);

	if( (GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT ||
		(GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_SINGLESEL) != LVS_SINGLESEL )
	{
		ASSERT(0);
		return;
	}

	if(nRow > m_pListCtrl->GetItemCount() || nRow < 0)
		return;

	BOOL bSet = FALSE;
	int nItem = -1;
	POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
	while(pos)
	{
		nItem = m_pListCtrl->GetNextSelectedItem(pos);
		if(nItem == nRow)
		{
			bSet = TRUE;
			continue;
		}
		m_pListCtrl->SetItemState(nItem, ~LVIS_SELECTED, LVIS_SELECTED);
	}

	if(bSet) return;
	m_pListCtrl->SetItemState(nRow, LVIS_SELECTED, LVIS_SELECTED);
}

int CHReportListBase::GetCurSel()
{
	ASSERT(m_pListCtrl != NULL);

	if( (GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT ||
		(GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_SINGLESEL) != LVS_SINGLESEL )
	{
		ASSERT(0);
		return -1;
	}

	POSITION pos = m_pListCtrl->GetFirstSelectedItemPosition();
	if(pos == NULL)
		return -1;

	return m_pListCtrl->GetNextSelectedItem(pos);
}

int CHReportListBase::CalcNextSel(int nRow)
{
	ASSERT(m_pListCtrl != NULL);

	if( (GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
	{
		ASSERT(0);
		return -1;
	}	

	int nCount = m_pListCtrl->GetItemCount();

	if(nRow < 0 || nCount == 0)
		return -1;

	if(nRow >= nCount)
		return nCount;

	return nRow;
}

void CHReportListBase::SetUsedStyle(BOOL bFullRowSelect, BOOL bShowGridLines, BOOL bSingSel)
{
	ASSERT(m_pListCtrl != NULL);

	DWORD dwStyle = m_pListCtrl->GetExtendedStyle();

	if(bFullRowSelect)
		dwStyle |= LVS_EX_FULLROWSELECT;
	else
		dwStyle &= ~LVS_EX_FULLROWSELECT;

	if(bShowGridLines)
		dwStyle |= LVS_EX_GRIDLINES;
	else
		dwStyle &= ~LVS_EX_GRIDLINES;

	m_pListCtrl->SetExtendedStyle(dwStyle);

	if(bSingSel)
		m_pListCtrl->ModifyStyle(0, LVS_SINGLESEL);
	else
		m_pListCtrl->ModifyStyle(LVS_SINGLESEL, 0);
}

BOOL CHReportListBase::OnNotifyImpl(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	ASSERT(m_pListCtrl != NULL);

	HD_NOTIFY *pHDNotify = (HD_NOTIFY*)lParam;
	switch( pHDNotify->hdr.code )
	{
	case HDN_ITEMCLICKA:
	case HDN_ITEMCLICKW:
		{
			if (!m_flatHeader.GetSafeHwnd())
				break;

			if (pHDNotify->iButton == 0)
			{
				if (pHDNotify->iItem == m_nSortedCol) 
					m_bAscending = !m_bAscending;
				else 
					m_bAscending = TRUE;
			}
			else 
			{
				break;
			}

			// set sort image for header.
			m_nSortedCol = pHDNotify->iItem;
			m_flatHeader.SetSortImage (m_nSortedCol, m_bAscending);
			SortList (m_nSortedCol, m_bAscending != FALSE);
		}
		break;
	}

	return m_pListCtrl->CListCtrl::OnNotify(wParam, lParam, pResult);
}

void CHReportListBase::PreSubclassWindowImpl_Post() 
{
	ASSERT(m_pListCtrl != NULL);

	if (m_bAutoFont)
	{
		InitFont();
		m_pListCtrl->SendMessage(WM_SETFONT, (WPARAM)(HFONT)m_font, MAKELPARAM(TRUE,0));
	}
}

int CHReportListBase::OnCreateImpl_Post(LPCREATESTRUCT lpCreateStruct) 
{
	ASSERT(m_pListCtrl != NULL);

	SetUsedStyle(TRUE, FALSE, 0);
	SubclassHeader();
	m_flatHeader.ShowSortArrow(TRUE);
	if(m_imageList.GetSafeHandle() == NULL)
		m_imageList.Create(m_nIconWidth, m_nLineHeight, ILC_COLOR24|ILC_MASK, 2, 2);
	m_pListCtrl->SetImageList(&m_imageList, LVSIL_SMALL);

	if (m_bAutoFont )
	{
		InitFont();
		m_pListCtrl->SetFont(&m_font);
	}
	
	return 0;
}

void CHReportListBase::OnCustomDrawImpl(NMHDR* pNMHDR, LRESULT* pResult)
{
	LPNMLVCUSTOMDRAW pLVCD = (LPNMLVCUSTOMDRAW)pNMHDR;
	*pResult = CDRF_DODEFAULT;
	int nItem = -1;
	
	switch(pLVCD->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW;
		break;
		
	case CDDS_ITEMPREPAINT:
		nItem = static_cast<int> (pLVCD->nmcd.dwItemSpec);
		if( OnCustomDrawItem(nItem, pLVCD->clrText, pLVCD->clrTextBk) )
			*pResult = CDRF_NOTIFYSUBITEMDRAW;
		else
			*pResult = CDRF_DODEFAULT;
		break;

	case CDDS_SUBITEM | CDDS_PREPAINT | CDDS_ITEM:
		nItem = static_cast<int> (pLVCD->nmcd.dwItemSpec);
		int nSubItem = pLVCD->iSubItem;
		OnCustomDrawSubItem(nItem, nSubItem, pLVCD->clrText, pLVCD->clrTextBk);
		break;
	}
}

void CHReportListBase::OnDestroyImpl_Pre()
{
	if( m_bAutoSave ) 
		SaveColumnWidths();
}

BOOL CHReportListBase::OnEraseBkgndImpl(CDC* pDC)
{
	return TRUE;
}

void CHReportListBase::OnPaintImpl()
{
	ASSERT(m_pListCtrl != NULL);

	if( (::GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
	{
		ASSERT(0);
		return;
	}

	CPaintDC dc(m_pListCtrl);
	CRect rectClient;
	m_pListCtrl->GetClientRect(&rectClient);

	CHeaderCtrl* pWndHeader = GetHeaderCtrlX();
	ASSERT(pWndHeader != NULL);
	CRect rcHeader;
	pWndHeader->GetWindowRect(&rcHeader);
	m_pListCtrl->ScreenToClient(&rcHeader);
	dc.ExcludeClipRect(&rcHeader);

	CHMemDC memDC(&dc, rectClient, ::GetSysColor(COLOR_WINDOW));

	m_pListCtrl->CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
}

BOOL CHReportListBase::SubclassHeader()
{
	if( (GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
	{
		ASSERT(0);
		return FALSE;
	}

	if (::IsWindow(m_flatHeader.GetSafeHwnd()))
	{
		ASSERT(0);
		return FALSE;
	}

	HWND hWndHeader = GetHeaderCtrlX()->GetSafeHwnd();
	if (!m_flatHeader.SubclassWindow (hWndHeader))
		return false;

	m_flatHeader.InitializeHeader();
	return TRUE;
}

void CHReportListBase::InitFont()
{
	m_font.DeleteObject();

	CString strHorzFont = _T( "Tahoma" );

	NONCLIENTMETRICS ncm;
	ZeroMemory(&ncm, sizeof(NONCLIENTMETRICS));
	ncm.cbSize = sizeof(NONCLIENTMETRICS);
	SystemParametersInfo(SPI_GETNONCLIENTMETRICS,	sizeof(NONCLIENTMETRICS), &ncm, 0);

	LOGFONT lfHorz;
	ZeroMemory(&lfHorz, sizeof(LOGFONT));
	CopyMemory((void*)&lfHorz, (const void*)&(ncm.lfMenuFont), (DWORD)sizeof(LOGFONT));

	if ( FontExists( strHorzFont ) )
		_tcscpy( lfHorz.lfFaceName, strHorzFont );
	else
		ASSERT( FALSE );
	
	CreateSysFont( lfHorz, m_font );
}

static const TCHAR _OfficeFaceName[]	= _T("Tahoma");

static int CALLBACK EnumFontFamExProc(ENUMLOGFONTEX* pelf,
	NEWTEXTMETRICEX* lpntm, int FontType, LPVOID pThis)
{
	UNUSED_ALWAYS(lpntm);
	UNUSED_ALWAYS(FontType);
	UNUSED_ALWAYS(pThis);

	CString strFaceName(pelf->elfLogFont.lfFaceName);
	return strFaceName.Compare(_OfficeFaceName);
}

BOOL CHReportListBase::FontExists(CString &strFaceName)
{
	LOGFONT lfEnum;
	lfEnum.lfFaceName[ 0 ] = 0;
	lfEnum.lfCharSet = DEFAULT_CHARSET;

	CWindowDC dc( NULL );
	if ( ::EnumFontFamiliesEx( dc.m_hDC, &lfEnum, ( FONTENUMPROC )EnumFontFamExProc, 
								( LPARAM )&strFaceName, 0 ) == 0 )
	{
		return TRUE;
	}

	return FALSE;
}

BOOL CHReportListBase::CreateSysFont(LOGFONT &lf, CFont &font, long lfWeight, char lfUnderline, long lfOrientation, long lfEscapement)
{
	lf.lfWeight      = lfWeight;
	lf.lfOrientation = lfOrientation;
	lf.lfEscapement  = lfEscapement;
	lf.lfUnderline   = lfUnderline;

	if ( !font.CreateFontIndirect( &lf ) )
	{
		return FALSE;
	}

	return TRUE;
}

int CHReportListBase::HitTestEx(CPoint point, int& nCol)
{
	int colnum = 0;
	int row = m_pListCtrl->HitTest( point, NULL );
	
	nCol = 0;

	// Make sure that the ListView is in LVS_REPORT
	if( (GetWindowLong(m_pListCtrl->m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
		return row;

	// Get the top and bottom row visible
	row = m_pListCtrl->GetTopIndex();
	int bottom = row + m_pListCtrl->GetCountPerPage();
	if( bottom > m_pListCtrl->GetItemCount() )
		bottom = m_pListCtrl->GetItemCount();
	
	// get a pointer to the header control, if NULL return error.
	CHeaderCtrl* pHeaderCtrl = GetHeaderCtrlX();
	if (pHeaderCtrl == NULL)
		return -1;

	// Get the number of columns
	int nColumnCount = pHeaderCtrl->GetItemCount();

	for( ;row <= bottom; ++row)
	{
		CRect rect;
		m_pListCtrl->GetItemRect( row, &rect, LVIR_BOUNDS );
		if( rect.PtInRect(point) )
		{
			for( colnum = 0; colnum < nColumnCount; colnum++ )
			{
				int colwidth = m_pListCtrl->GetColumnWidth(colnum);
				if( point.x >= rect.left && point.x <= (rect.left + colwidth ) )
				{
					nCol = colnum;
					return row;
				}
				rect.left += colwidth;
			}
		}
	}

	return -1;
}